#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string>
#include <vector>
#include <functional>
#include <stdio.h>
#include <queue>
#include <semaphore.h>
using namespace std;

template <class T>
using fun = function<void(T &)>;

template <class T>
class mypthread
{
public:
    static void *pthread_function(void *formal)
    {
        mypthread<T> *tmp = static_cast<mypthread<T> *>(formal);
        tmp->work();
        return nullptr;
    }

    void work()
    {
        _fun(_data);
    }

    mypthread(string name, fun<T> function, T &data) : _name(name), _run(false), _fun(function), _data(data)
    {
    }

    ~mypthread()
    {
    }

    bool start()
    {
        int i = pthread_create(&_id, nullptr, pthread_function, this);
        if (i == 0)
        {
            _run = true;
        }
        else
        {
            return false;
        }
        return true;
    }

    void join()
    {
        if (_run)
        {
            pthread_join(_id, nullptr);
        }
    }

    void Detach()
    {
        if (_run)
        {
            pthread_detach(_id);
        }
    }

    void stop()
    {
        _run = false;
    }

private:
    string _name;
    pthread_t _id;
    bool _run;
    fun<T> _fun;
    T &_data;
};

template <class T>
class circular_queue
{
public:
    circular_queue(int max) : _max(max), _v(max)
    {
        sem_init(&_room, 0, _max);
        sem_init(&_data, 0, 0);
        pthread_mutex_init(&_producer_mutex,nullptr);
        pthread_mutex_init(&_consumer_mutex,nullptr);

        _room_pos = 0;
        _data_pos = 0;
    }

    ~circular_queue()
    {
        sem_destroy(&_room);
        sem_destroy(&_data);
        pthread_mutex_destroy(&_producer_mutex);
        pthread_mutex_destroy(&_consumer_mutex);

    }

    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }

    void lock(pthread_mutex_t& mutex)
    {
        pthread_mutex_lock(&mutex);
    }

    void unlock(pthread_mutex_t& mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

    void V(sem_t &sem)
    {
        sem_post(&sem);
    }

    void push(T &data)
    {
        // 申请信号量
        P(_room);
        lock(_producer_mutex);
        _v[_room_pos++] = data;
        _room_pos %= _max;

        V(_data);
        unlock(_producer_mutex);
    }

    void pop(T* ptr)
    {
        P(_data);
        lock(_consumer_mutex);
        *ptr = _v[_data_pos++];
        _data_pos %= _max;

        V(_room);
        unlock(_consumer_mutex);
    }

private:
    vector<T> _v;
    int _max;
    // 两个信号量
    sem_t _room;
    sem_t _data;

    // 两个下标
    int _room_pos;
    int _data_pos;

    // 一个锁
    pthread_mutex_t _producer_mutex;
    pthread_mutex_t _consumer_mutex;

};
